﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using GeoAPI.Geometries;
using NetTopologySuite.Geometries;
using NetTopologySuite.Utilities;

namespace NetTopologySuite.Noding
{
	public class SegmentNodeList : IEnumerable<object>, IEnumerable
	{
		public SegmentNodeList(NodedSegmentString edge)
		{
			this._edge = edge;
		}

		public NodedSegmentString Edge
		{
			get
			{
				return this._edge;
			}
		}

		public SegmentNode Add(Coordinate intPt, int segmentIndex)
		{
			SegmentNode segmentNode = new SegmentNode(this._edge, intPt, segmentIndex, this._edge.GetSegmentOctant(segmentIndex));
			object obj;
			if (this._nodeMap.TryGetValue(segmentNode, out obj))
			{
				SegmentNode segmentNode2 = (SegmentNode)obj;
				Assert.IsTrue(segmentNode2.Coord.Equals2D(intPt), "Found equal nodes with different coordinates");
				return segmentNode2;
			}
			this._nodeMap.Add(segmentNode, segmentNode);
			return segmentNode;
		}

		public IEnumerator<object> GetEnumerator()
		{
			return this._nodeMap.Values.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return this.GetEnumerator();
		}

		private void AddEndpoints()
		{
			int num = this._edge.Count - 1;
			this.Add(this._edge.GetCoordinate(0), 0);
			this.Add(this._edge.GetCoordinate(num), num);
		}

		private void AddCollapsedNodes()
		{
			IList<int> list = new List<int>();
			this.FindCollapsesFromInsertedNodes(list);
			this.FindCollapsesFromExistingVertices(list);
			foreach (int num in list)
			{
				this.Add(this._edge.GetCoordinate(num), num);
			}
		}

		private void FindCollapsesFromExistingVertices(IList<int> collapsedVertexIndexes)
		{
			for (int i = 0; i < this._edge.Count - 2; i++)
			{
				Coordinate coordinate = this._edge.GetCoordinate(i);
				Coordinate coordinate2 = this._edge.GetCoordinate(i + 2);
				if (coordinate.Equals2D(coordinate2))
				{
					collapsedVertexIndexes.Add(i + 1);
				}
			}
		}

		private void FindCollapsesFromInsertedNodes(IList<int> collapsedVertexIndexes)
		{
			int[] array = new int[1];
			IEnumerator<object> enumerator = this.GetEnumerator();
			enumerator.MoveNext();
			SegmentNode ei = (SegmentNode)enumerator.Current;
			while (enumerator.MoveNext())
			{
				object obj = enumerator.Current;
				SegmentNode segmentNode = (SegmentNode)obj;
				if (SegmentNodeList.FindCollapseIndex(ei, segmentNode, array))
				{
					collapsedVertexIndexes.Add(array[0]);
				}
				ei = segmentNode;
			}
		}

		private static bool FindCollapseIndex(SegmentNode ei0, SegmentNode ei1, int[] collapsedVertexIndex)
		{
			if (!ei0.Coord.Equals2D(ei1.Coord))
			{
				return false;
			}
			int num = ei1.SegmentIndex - ei0.SegmentIndex;
			if (!ei1.IsInterior)
			{
				num--;
			}
			if (num == 1)
			{
				collapsedVertexIndex[0] = ei0.SegmentIndex + 1;
				return true;
			}
			return false;
		}

		public void AddSplitEdges(IList<ISegmentString> edgeList)
		{
			this.AddEndpoints();
			this.AddCollapsedNodes();
			IEnumerator<object> enumerator = this.GetEnumerator();
			enumerator.MoveNext();
			SegmentNode ei = (SegmentNode)enumerator.Current;
			while (enumerator.MoveNext())
			{
				object obj = enumerator.Current;
				SegmentNode segmentNode = (SegmentNode)obj;
				ISegmentString item = this.CreateSplitEdge(ei, segmentNode);
				edgeList.Add(item);
				ei = segmentNode;
			}
		}

		private ISegmentString CreateSplitEdge(SegmentNode ei0, SegmentNode ei1)
		{
			int num = ei1.SegmentIndex - ei0.SegmentIndex + 2;
			Coordinate coordinate = this._edge.GetCoordinate(ei1.SegmentIndex);
			bool flag = ei1.IsInterior || !ei1.Coord.Equals2D(coordinate);
			if (!flag)
			{
				num--;
			}
			Coordinate[] array = new Coordinate[num];
			int num2 = 0;
			array[num2++] = new Coordinate(ei0.Coord);
			for (int i = ei0.SegmentIndex + 1; i <= ei1.SegmentIndex; i++)
			{
				array[num2++] = this._edge.GetCoordinate(i);
			}
			if (flag)
			{
				array[num2] = new Coordinate(ei1.Coord);
			}
			return new NodedSegmentString(array, this._edge.Context);
		}

		public Coordinate[] GetSplitCoordinates()
		{
			CoordinateList coordinateList = new CoordinateList();
			this.AddEndpoints();
			IEnumerator<object> enumerator = this.GetEnumerator();
			enumerator.MoveNext();
			SegmentNode ei = (SegmentNode)enumerator.Current;
			while (enumerator.MoveNext())
			{
				object obj = enumerator.Current;
				SegmentNode segmentNode = (SegmentNode)obj;
				this.AddEdgeCoordinates(ei, segmentNode, coordinateList);
				ei = segmentNode;
			}
			return coordinateList.ToCoordinateArray();
		}

		private void AddEdgeCoordinates(SegmentNode ei0, SegmentNode ei1, CoordinateList coordList)
		{
			int num = ei1.SegmentIndex - ei0.SegmentIndex + 2;
			Coordinate coordinate = this._edge.GetCoordinate(ei1.SegmentIndex);
			bool flag = ei1.IsInterior || !ei1.Coord.Equals2D(coordinate);
			if (!flag)
			{
				num--;
			}
			coordList.Add(new Coordinate(ei0.Coord), false);
			for (int i = ei0.SegmentIndex + 1; i <= ei1.SegmentIndex; i++)
			{
				coordList.Add(this._edge.GetCoordinate(i));
			}
			if (flag)
			{
				coordList.Add(new Coordinate(ei1.Coord));
			}
		}

		public void Write(StreamWriter outstream)
		{
			outstream.Write("Intersections:");
			foreach (object obj in this)
			{
				((SegmentNode)obj).Write(outstream);
			}
		}

		private readonly IDictionary<SegmentNode, object> _nodeMap = new SortedDictionary<SegmentNode, object>();

		private readonly NodedSegmentString _edge;
	}
}
